package drone.iqgc.common ;

import java.io.IOException ;
import java.util.Collections ;
import java.util.HashSet ;
import java.util.Set ;

import javax.annotation.PostConstruct ;
import javax.websocket.OnClose ;
import javax.websocket.OnError ;
import javax.websocket.OnMessage ;
import javax.websocket.OnOpen ;
import javax.websocket.Session ;
import javax.websocket.server.ServerEndpoint ;

import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.stereotype.Component ;

import com.alibaba.fastjson.JSONObject ;

import drone.basis.util.StringUtil ;
import drone.iqgc.service.CommandService ;

@ServerEndpoint ( value = "/websocket" )
@Component
public class WebsocketServer
{

	private static final Logger logger = LoggerFactory.getLogger ( WebsocketServer.class ) ;

	private static Set < Session > SESSIONS = Collections.synchronizedSet ( new HashSet < Session > ( ) ) ;

	@PostConstruct
	public void init ( )
	{
	}

	@OnOpen
	public void onOpen (
			Session session
	)
	{
		if ( ! SESSIONS.contains ( session ) )
		{
			SESSIONS.add ( session ) ;
		}
		logger.info ( "Monitor Open : " + session.getId ( ) + " | Monitor Pool Size : " + SESSIONS.size ( ) ) ;
	}

	@OnClose
	public void onClose (
			Session session
	)
	{
		SESSIONS.remove ( session ) ;
		logger.info ( "Monitor Close : " + session.getId ( ) + " | Monitor Pool Size : " + SESSIONS.size ( ) ) ;
	}

	@OnMessage
	public void onMessage (
			String message ,
			Session session
	)
	{

		if ( StringUtil.isEmpty ( message ) )
		{
			return ;
		}

		if ( message.equals ( "heart" ) )
		{
			return ;
		}

		System.out.println ( message ) ;

		CommandService commandService = ( CommandService ) ContextAware.getBean ( "commandService" ) ;

		JSONObject object = JSONObject.parseObject ( message ) ;

		// 拉取状态
		switch ( object.getString ( "name" ) )
		{
			case "status" :
				commandService.droneStatusCommand ( object.getString ( "target" ) ) ;
				break ;
			case "position" :
				commandService.dronePositionCommand ( object.getString ( "target" ) ) ;
				break ;
			case "flightmode" :
				commandService.droneFlightmodeCommand ( object.getString ( "target" ) ) ;
				break ;
			case "maxspeed" :
				commandService.droneMaxspeedCommand ( object.getString ( "target" ) ) ;
				break ;
			case "home" :
				commandService.droneHomeCommand ( object.getString ( "target" ) ) ;
				break ;
			case "goto" :
				commandService.droneGotoCommand ( object.getString ( "target" ) , object.getJSONObject ( "data" ).getString ( "speed" ) , object.getJSONObject ( "data" ).getString ( "lng" ) ,
						object.getJSONObject ( "data" ).getString ( "lat" ) ) ;
				break ;
			case "takeoff" :
				commandService.droneTakeoffCommand ( object.getString ( "target" ) , object.getJSONObject ( "data" ).getString ( "alt" ) ) ;
				break ;
			case "land" :
				commandService.droneLandCommand ( object.getString ( "target" ) ) ;
				break ;
			case "return" :
				commandService.droneReturnCommand ( object.getString ( "target" ) ) ;
				break ;
			case "altitude" :
				commandService.droneAltitudeCommand ( object.getString ( "target" ) , object.getJSONObject ( "data" ).getString ( "alt" ) ) ;
				break ;
			case "camera" :
				commandService.droneCameraCommand ( object.getString ( "target" ) ) ;
				break ;
			case "missionUpload" :
				commandService.droneMissionUploadCommand ( object.getString ( "target" ) , object.getJSONArray ( "data" ) ) ;
				break ;
			case "missionDownload" :
				commandService.droneMissionDownloadCommand ( object.getString ( "target" ) ) ;
				break ;
			case "missionStart" :
				commandService.droneMissionStartCommand ( object.getString ( "target" ) ) ;
				break ;
			case "missionCanel" :
				commandService.droneMissionCanelCommand ( object.getString ( "target" ) ) ;
				break ;
			default :
				break ;
		}

	}

	@OnError
	public void onError (
			Session session ,
			Throwable error
	)
	{
		logger.info ( "Monitor Error : " + session.getId ( ) + " | Monitor Pool Size : " + SESSIONS.size ( ) ) ;

		error.printStackTrace ( ) ;

		try
		{
			logger.info ( "Monitor Error Close : " + session.getId ( ) + " | Alarm Pool Size : " + SESSIONS.size ( ) ) ;
			session.close ( ) ;
		} catch ( IOException e )
		{
			e.printStackTrace ( ) ;
		}
	}

	public static void message (
			String message
	)
	{

		for ( Session session : SESSIONS )
		{
			synchronized ( session )
			{
				try
				{
					session.getBasicRemote ( ).sendText ( message ) ;
				} catch ( IOException exception )
				{
					logger.info ( "Monitor Message Exception: " + session.getId ( ) + " Message : " + message ) ;
					// exception.printStackTrace ( ) ;
				}
			}
		}

	}

	public static void heart ( )
	{

		logger.info ( "Monitor Heart Initial: " + SESSIONS.size ( ) ) ;

		for ( Session session : SESSIONS )
		{

			if ( session.isOpen ( ) )
			{
				logger.info ( "Monitor Heart : " + session.getId ( ) ) ;

				synchronized ( session )
				{
					try
					{
						session.getBasicRemote ( ).sendText ( "heart" ) ;
					} catch ( IOException exception )
					{
						logger.info ( "Monitor Heart Exception: " + session.getId ( ) ) ;
						exception.printStackTrace ( ) ;
					}
				}

			} else
			{
				logger.info ( "Monitor Heart Closed: " + session.getId ( ) ) ;
			}

		}

	}

}
